﻿using BookSleeve;
using CalcEngine;
using Castle.Core.Configuration;
using Inovout.Application;
using Inovout.Data.HBase;
using Inovout.Services;
using Inovout.YunYao.Models;
using Inovout.YunYao.Repositories;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace Inovout.YunYao.Services
{
    public class SolutionService : RepositoryService<Solution>, IRepositoryService<Solution>, ISolutionService
    {
        protected SolutionRepository SolutionRepository
        {
            get
            {
                return (SolutionRepository)base.Repository;
            }
        }
        public Solution FindByCode(int code)
        {
            return SolutionRepository.FindByCode(code);
        }

        public override void Save(Solution solution)
        {
            //ToDo 未来需采用Castle新的事务管理组件。因为原先版本已不再更新。
            if (solution.Id == null)
            {
                Solution lastSolution = SolutionRepository.LastOrDefault("Code");
                if (lastSolution == null)
                {
                    solution.Code = 110;
                }
                else
                {
                    solution.Code = lastSolution.Code + 1;
                }
                SolutionApplication solutionApplication = new SolutionApplication { Solution = solution };
                //AppKey暂定与Code相同，暂时不用密钥，即不验证数据完整性。
                solutionApplication.Key = solution.Code.ToString();
                solutionApplication.Token = Guid.NewGuid().ToString("N");
                base.Save(solution);
                IRepositoryService<SolutionApplication> solutionApplicationService = ComponentRegistry.Resolve<IRepositoryService<SolutionApplication>>();
                solutionApplicationService.Save(solutionApplication);
                UpdateRedis(solutionApplication);
                CreateHBaseTable(solutionApplication);
            }
            else
            {
                base.Save(solution);
            }
        }
        private void CreateHBaseTable(SolutionApplication solutionApplication)
        {
            IApplication application = ComponentRegistry.Resolve<IApplication>();
            IConfiguration hbaseConfiguration = application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("hbase"));
            using (HBaseConnection hbaseConnection
                = new HBaseConnection(hbaseConfiguration.Attributes["ip"].Trim(),
                    int.Parse(hbaseConfiguration.Attributes["port"].Trim())))
            {
                hbaseConnection.Open();
                hbaseConnection.CreateTableCommand().CreateTable(hbaseConfiguration.Attributes["tableNamePrefix"].Trim() + solutionApplication.Solution.Code.ToString(),
                    new ColumnDescriptor[]{
                        new ColumnDescriptor { Name = UTF8Encoding.UTF8.GetBytes("monitor"),MaxVersions=int.MaxValue,TimeToLive=int.MaxValue },
                        new ColumnDescriptor { Name = UTF8Encoding.UTF8.GetBytes("solution"),MaxVersions=int.MaxValue,TimeToLive=int.MaxValue }
                    });
            }
        }
        private void UpdateRedis(SolutionApplication solutionApplication)
        {
            IApplication application = ComponentRegistry.Resolve<IApplication>();
            IConfiguration redisConfiguration = application.Configuration.Children["redis"];
            using (var redisConnection
                = new RedisConnection(redisConfiguration.Attributes["ip"], int.Parse(redisConfiguration.Attributes["port"].Trim())))
            {
                redisConnection.Open();
                int dbid = int.Parse(redisConfiguration.Attributes["dbid"].Trim());
                Dictionary<string, byte[]> solutionApplicationRedisDictionary = new Dictionary<string, byte[]> { 
                    {"appkey",UTF8Encoding.UTF8.GetBytes(solutionApplication.Key)},
                    {"sln",UTF8Encoding.UTF8.GetBytes(solutionApplication.Solution.Code.ToString())}
                };
                if (!string.IsNullOrEmpty(solutionApplication.Secret))
                {
                    solutionApplicationRedisDictionary.Add("appsecret", UTF8Encoding.UTF8.GetBytes(solutionApplication.Secret));

                }
                redisConnection.Hashes.Set(dbid, solutionApplication.Token, solutionApplicationRedisDictionary, true);
                redisConnection.Keys.Expire(dbid, solutionApplication.Token, int.MaxValue, true);



            }
        }

        public void FlushNginxConfig()
        {
            IRepositoryService<MonitoringNode> monitoringNodeService = ComponentRegistry.Resolve<IRepositoryService<MonitoringNode>>();
            IList<MonitoringNode> monitoringNodes = monitoringNodeService.FindAll();
            StringBuilder stringBuilder = new StringBuilder("quality_formulas =  { ");
            LuaCodeBuilder luaCodeBuilder = null;
            CodeCalcEngine codeCalcEngine = null;
            bool needSplitSymbol = false;
            foreach (var monitoringNode in monitoringNodes)
            {
                if (!string.IsNullOrEmpty(monitoringNode.FeatureValueDescriptor.QualityFormula))
                {
                    luaCodeBuilder = new LuaCodeBuilder("quality", stringBuilder);
                    codeCalcEngine = new CodeCalcEngine(luaCodeBuilder);
                    if (needSplitSymbol)
                    {
                        stringBuilder.Append(",");
                    }
                    needSplitSymbol = true;
                    stringBuilder.Append("[\"" + monitoringNode.Code + "\"]=function(node)" + luaCodeBuilder.NewLine);
                    object result = codeCalcEngine.Parse(monitoringNode.FeatureValueDescriptor.QualityFormula).Evaluate();

                    if (string.IsNullOrEmpty(monitoringNode.FeatureValueDescriptor.BadQualityFormula))
                    {
                        stringBuilder.Append("local is_bad_quality = false" + luaCodeBuilder.NewLine);
                    }
                    else
                    {
                        luaCodeBuilder = new LuaCodeBuilder("is_bad_quality", stringBuilder);
                        codeCalcEngine = new CodeCalcEngine(luaCodeBuilder);
                        result = codeCalcEngine.Parse(monitoringNode.FeatureValueDescriptor.BadQualityFormula).Evaluate();
                    }
                    stringBuilder.Append("return quality,is_bad_quality" + luaCodeBuilder.NewLine);
                    stringBuilder.Append("end" + luaCodeBuilder.NewLine);
                }
            }
            stringBuilder.Append("}");
            IApplication application = ComponentRegistry.Resolve<IApplication>();
            IConfiguration luaShareFolderConfiguration = application.Configuration.Children["luaShareFolder"];
            //写入共享文件夹
            ConnectLan(luaShareFolderConfiguration.Attributes["path"].Trim(), luaShareFolderConfiguration.Attributes["userName"].Trim(), luaShareFolderConfiguration.Attributes["password"].Trim());
            DirectoryInfo directoryInfo = new DirectoryInfo(luaShareFolderConfiguration.Attributes["path"].Trim());
            if (!directoryInfo.Exists)
            {
                directoryInfo.Create();
            }
            string fileName = "node_quality_formulas_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".lua";
            using (FileStream fileStream = new FileStream(Path.Combine(directoryInfo.FullName, fileName), FileMode.Create))
            {
                byte[] buffer = System.Text.UTF8Encoding.UTF8.GetBytes(stringBuilder.ToString());
                fileStream.Write(buffer, 0, buffer.Length);
            }
            //调用远程HttpLinuxShell
            IConfiguration nginxServerConfiguration = application.Configuration.Children["nginxServer"];
            foreach (IConfiguration nginxServer in nginxServerConfiguration.Children)
            {
                WebRequest webRequest = WebRequest.Create(nginxServer.Attributes["uri"].Trim());

                webRequest.Method = "POST";
                Stream stream = webRequest.GetRequestStream();

                byte[] buffer = null;
                //buffer = UTF8Encoding.UTF8.GetBytes("cmd=ps");
                //stream.Write(buffer, 0, buffer.Length);
                string mountPath = "/mnt/" + Guid.NewGuid().ToString("N") + "/";
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=mkdir " + mountPath);
                stream.Write(buffer, 0, buffer.Length);

                buffer = UTF8Encoding.UTF8.GetBytes(
                        string.Format("&cmd=mount -t cifs -o username=\"{0}\",password=\"{1}\" {2} {3}",
                                        luaShareFolderConfiguration.Attributes["userName"].Trim(),
                                        luaShareFolderConfiguration.Attributes["password"].Trim(),
                                        directoryInfo.FullName.Replace(@"\", "/"), mountPath));
                stream.Write(buffer, 0, buffer.Length);
                string linuxFile = "/usr/local/openresty/lualib/yunyao/node_quality_formula.lua";
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=rm -f " + linuxFile);
                stream.Write(buffer, 0, buffer.Length);
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=cp " + mountPath + fileName + " " + linuxFile);
                stream.Write(buffer, 0, buffer.Length);
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=service nginxd reload");
                stream.Write(buffer, 0, buffer.Length);
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=umount " + mountPath);
                stream.Write(buffer, 0, buffer.Length);
                buffer = UTF8Encoding.UTF8.GetBytes(@"&cmd=rmdir " + mountPath);
                stream.Write(buffer, 0, buffer.Length);



                webRequest.ContentType = "application/x-www-form-urlencoded";

                WebResponse webResponse = webRequest.GetResponse();
                string result;
                using (Stream responSestream = webResponse.GetResponseStream())
                {
                    result = new StreamReader(responSestream).ReadToEnd();
                }
            }
        }
        private string ConnectLan(string server, string userName, string password)
        {
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.CreateNoWindow = true;
            process.Start();
            //NET USE //192.168.0.1 PASSWORD /USER:UserName 
            process.StandardInput.WriteLine("net use " + server + " " + password + " /user:" + userName);

            process.StandardInput.WriteLine("exit");
            process.WaitForExit();
            string result = process.StandardOutput.ReadToEnd();// 得到cmd.exe的输出  
            string errormsg = process.StandardError.ReadToEnd();
            process.Close();
            return result;
        }
    }
}
